package net.cloudcodex.client.character.handler;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;

import net.cloudcodex.client.CloudCodexEventBus;
import net.cloudcodex.client.storyboard.cdo.CharacterKeyCDO;
import net.cloudcodex.client.util.rpc.SuccessCallback;
import net.cloudcodex.shared.dto.Result;
import net.cloudcodex.shared.dto.campaign.character.CharacterDescriptionDTO;
import net.cloudcodex.shared.rpc.CampaignRPC;
import net.cloudcodex.shared.rpc.CampaignRPCAsync;

import com.google.inject.Inject;
import com.mvp4g.client.annotation.EventHandler;
import com.mvp4g.client.event.BaseEventHandler;

/**
 * Client-side cache of CharacterDescriptionDTO.
 * 
 * Deals with server-side service {@link CampaignRPC#getCharacterDescription}.
 * 
 * @author ADaroussin
 */
@EventHandler
public class CharacterDescriptionEventHandler extends BaseEventHandler<CloudCodexEventBus> {

	protected final CampaignRPCAsync service;

	protected final SortedMap<CharacterKeyCDO, CharacterDescriptionDTO> cdCaches = new TreeMap<CharacterKeyCDO, CharacterDescriptionDTO>();

	protected final SortedMap<CharacterKeyCDO, List<SuccessCallback<CharacterDescriptionDTO>>> cdCallbacks = new TreeMap<CharacterKeyCDO, List<SuccessCallback<CharacterDescriptionDTO>>>();

	protected final SuccessCallback<Result<CharacterDescriptionDTO>> cdCallback = new SuccessCallback<Result<CharacterDescriptionDTO>>() {
		@Override
		public void onSuccess(Result<CharacterDescriptionDTO> result) {
			final CharacterDescriptionDTO cd = result.getData();
			final long campaignId = cd.getCampaignId();
			final long characterId = cd.getId();
			final CharacterKeyCDO characterKey = new CharacterKeyCDO(campaignId, characterId);
			cdCaches.put(characterKey, cd);
			final List<SuccessCallback<CharacterDescriptionDTO>> callbacks = cdCallbacks.remove(characterKey);
			for (SuccessCallback<CharacterDescriptionDTO> callback : callbacks) {
				// Send result to registered callback
				callback.onSuccess(cd);
			}
		}
	};

	@Inject
	public CharacterDescriptionEventHandler(CampaignRPCAsync service) {
		this.service = service;
	}

	public void onGetCharacterDescription(long campaignId, long characterId,
			SuccessCallback<CharacterDescriptionDTO> callback) {
		final CharacterKeyCDO characterKey = new CharacterKeyCDO(campaignId, characterId);
		final CharacterDescriptionDTO cd = cdCaches.get(characterKey);
		if (cd == null) {
			List<SuccessCallback<CharacterDescriptionDTO>> callbacks = cdCallbacks.get(characterKey);
			if (callbacks == null) {
				// First callback: init
				callbacks = new ArrayList<SuccessCallback<CharacterDescriptionDTO>>();
				callbacks.add(callback);
				// Calls the server-side service
				service.getCharacterDescription(campaignId, characterId, null, new Date(), cdCallback);
			} else {
				// Add with others callbacks
				callbacks.add(callback);
			}
		} else {
			// CharacterDescriptionDTO already in the cache: just send it
			callback.onSuccess(cd);
		}
	}
}
